home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NetNews Offline 2
/
NetNews Offline Volume 2.iso
/
news
/
comp
/
std
/
c
/
762
< prev
next >
Wrap
Text File
|
1996-08-06
|
5KB
|
106 lines
Path: xylogics.com!not-for-mail
From: carlson@xylogics.com (James Carlson)
Newsgroups: comp.std.c
Subject: Re: Q: char **foo, char *foo[], and char foo[][] ?
Date: 18 Apr 1996 08:05:28 -0400
Organization: Xylogics Incorporated
Distribution: world
Message-ID: <4l5b68$kg2@newhub.xylogics.com>
References: <4l33ok$oo2@Sherlock.lectra.fr>
Reply-To: carlson@xylogics.com
NNTP-Posting-Host: newhub.xylogics.com
In article <4l33ok$oo2@Sherlock.lectra.fr>, phil@rd.lectra.fr (Philippe Maurisset) writes:
|> Considering the 3 following declarations:
|>
|> 1 - char **foo;
|> 2 - char *foo[];
|> 3 - char foo[][];
|>
[...non-working example deleted...]
|> Can anybody help me ? Is it system-dependent ?
No, it's not system-dependent, but it is context-specific.
There are some rules you can follow. When you define a simple array
(all []'s, like foo[3][9]), you can refer to it in prototypes either as
fully-dimensioned (all []'s with constant values, like foo[3][9]), or
with the first dimension elided (all but first [] with constant, like
foo[][9]), or even as a simple pointer (like *foo or foo[]), although
the dimensioning will be lost and the elements will appear as a single-
dimension array (27 elements in this case). You may not refer to it as
"*foo[]", either as an argument declarator or in an "extern" in a
separate file.
When you create an array of pointers (like *foo[3][2]), you can refer to
it in prototypes either as the same type of pointer (*foo[3][2] again),
or with the first dimension elided (*foo[][2]), or even as a simple
pointer (**foo), though, again, you drop back to single-dimension.
The pattern here is that the first set of brackets ([]) translate into
one level of "*" in the function argument declaration, but additional
levels of brackets do NOT add "*"s to the function argument. Thus,
char foo[1000] and char foo[10][10][10] are stored in exactly the same
internal format, and can be referred to in a function argument list as
foo[1000], foo[], foo[][10][10], foo[10][10][10], or *foo.
One more wrinkle to consider is that when declaring a variable, *foo is
different from (and incompatible with) foo[], but when passed as an
argument, they are identical. Thus, when making "extern" statements to
refer to a variable (rather than passing as an argument list), do not
follow the above rules, but rather declare variable exactly as
originally defined. The only exception to that rule is that you may
still elide the first dimension in an extern (like foo[][9]), but,
again, you cannot choose to call this "*foo" in the extern.
Instead of trying to argue about the abstract types, let's instead look
at a hypothetical example on an imaginary machine.
char **var1;
char *var2[5];
char var3[3][2];
These three declarations could produce the following assembly code for
our hypothetical machine (assuming 32-bit architecture, nice, simple
system):
.bss var1,4 # single char** pointer, 4 bytes
.bss var2,20 # five char* pointers, 20 bytes
.bss var3,6 # array of 3x2 chars, 6 bytes
Note that these are extremely different. The first case declares a
single simple pointer, which happens to be a pointer-to-a-pointer. The
second declares a contiguous array of 5 pointers, each of which happens
to be a pointer-to-a-char. The last example just creates a block of 6
bytes, no pointers.
Because the types are different, the compiler knows to generate
different code for accessing each case. Let's carry this a little
further and fetch var3[2][1], var2[2][1], and var1[2][1]. These look
like (two register machine, "ptr" and "acc"):
move (var3+5),acc # move offset 2*2+1 into accum.
move (var2+8),ptr # move offset 2*4 into pointer
move 1(ptr),acc # move offset 1 into accumul.
move var3,ptr # fetch var3 (pointer)
move 8(ptr),ptr # move offset 2*4 into pointer
move 1(ptr),acc # move offset 1 into accumul.
In the first case, the compiler uses the "var3" symbol as the location
of the beginning of the array, and simply needs to offset out to the
6th location to fetch the desired character. In the second case, the
compiler can locate var2[2] immediately; it's the second element in the
var2 array (pointers of 4 bytes each), but then it must use the value at
that location as a pointer to the actual array of characters, and then
fetch offset 1 from there. In the last case, the compiler must fetch
the contents of var3, treat it as a pointer to fetch the 2nd pointer
value (again 4 bytes each), and then fetch offset 1 from that value.
--
James Carlson <carlson@xylogics.com> Tel: +1 617 272 8140
Annex Interface Development / Xylogics, Inc. +1 800 225 3317
53 Third Avenue / Burlington MA 01803-4491 Fax: +1 617 272 2618